package com.inspur.security.cbb3.kms.config.security;

import com.inspur.security.cbb3.kms.sysuser.po.SysUserBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

/**
 * security配置
 * @author lijunchang
 */
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {

    private final JwtAuthenticationEntryPoint unauthorizedHandler;
    private final JwtAuthenticationTokenFilter authenticationTokenFilter;
    private final AccessDeniedHandler accessDeniedHandler;
    private final UserDetailsService customUserDetailsService;
    @Autowired
    public WebSecurityConfig(JwtAuthenticationEntryPoint unauthorizedHandler,
                             @Qualifier("RestAuthenticationAccessDeniedHandler") AccessDeniedHandler accessDeniedHandler,
                             @Qualifier("CustomUserDetailsService") UserDetailsService customUserDetailsService,
                             JwtAuthenticationTokenFilter authenticationTokenFilter) {
        this.unauthorizedHandler = unauthorizedHandler;
        this.accessDeniedHandler = accessDeniedHandler;
        this.customUserDetailsService = customUserDetailsService;
        this.authenticationTokenFilter = authenticationTokenFilter;
    }

    /**
     * 装载BCrypt密码编码器
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Autowired
    public void configureAuthentication(AuthenticationManagerBuilder authenticationManagerBuilder) throws Exception {
        authenticationManagerBuilder
//                // 设置UserDetailsService
                .userDetailsService(this.customUserDetailsService)
//                // 使用BCrypt进行密码的hash
                .passwordEncoder(passwordEncoder());
    }

    @Override
    protected void configure(HttpSecurity httpSecurity) throws Exception {

        // 禁用缓存
        httpSecurity.headers().cacheControl();
        //安全配置
        httpSecurity.headers().contentSecurityPolicy("default-src 'none';" +
                "    script-src 'self' 'unsafe-inline' 'unsafe-eval';" +
                "    connect-src 'self';" +
                "    img-src 'self' data:;"+
                "    frame-src 'self';"+
                "    font-src 'self';"+
                "    object-src 'self';"+
                "    style-src 'self' 'unsafe-inline';" +
                "    media-src 'self';"
        )
                .and().frameOptions().sameOrigin().contentTypeOptions()
                .and().httpStrictTransportSecurity().maxAgeInSeconds(31536000).includeSubDomains(true)
                .and().xssProtection()
        ;
        // 由于使用的是JWT，我们这里不需要csrf
        httpSecurity.csrf().disable();
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);

        httpSecurity
                .exceptionHandling().accessDeniedHandler(accessDeniedHandler).authenticationEntryPoint(unauthorizedHandler).and()
                // 基于token，所以不需要session
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                .authorizeRequests()

                // swagger start
                .antMatchers("/swagger-ui.html").permitAll()
                .antMatchers("/swagger-resources/**").permitAll()
                .antMatchers("/images/**").permitAll()
                .antMatchers("/webjars/**").permitAll()
                .antMatchers("/v2/api-docs").permitAll()
                .antMatchers("/configuration/ui").permitAll()
                .antMatchers("/configuration/security").permitAll()
                // swagger end
                .antMatchers(
//                        "/",
                        "/**/favicon.ico"
//                        "/static/**",
//                        "/templates/**",
//                        "/error/**"
                ).permitAll()

                // 对于获取token的rest api要允许匿名访问
                .antMatchers( "/v1/doLogin").permitAll()
                .antMatchers( "/test/**").permitAll()
                .antMatchers( "/v1/sysuser/pwd").hasAnyAuthority(SysUserBean.USER_TYPE_ADMIN,SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/sysuser/**").hasAuthority(SysUserBean.USER_TYPE_ADMIN)
                .antMatchers( "/v1/syslog/**").hasAuthority(SysUserBean.USER_TYPE_ADMIN)
                .antMatchers( "/v1/keyorders").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/keyorders/**").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/secrets").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/secrets/**").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/containers").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/containers/**").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/dataorders").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/dataorders/**").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/data/**").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/keks").hasAuthority(SysUserBean.USER_TYPE_PRO_ADMIN)
                .antMatchers( "/v1/cleanup").hasAuthority(SysUserBean.USER_TYPE_ADMIN)
//                例子：
                // 除上面外的所有请求全部需要鉴权认证
                .anyRequest().authenticated();
    }


    @Bean
    @Override
    public AuthenticationManager authenticationManagerBean() throws Exception {
        return super.authenticationManagerBean();
    }
}
